package cn.uexpo.lhz.controller.admin;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import cn.uexpo.lhz.biz.ImportLogBiz;
import cn.uexpo.lhz.biz.StaffBiz;
import cn.uexpo.lhz.common.oldBase.BaseController;
import cn.uexpo.lhz.common.oldUtils.StringDate;
import cn.uexpo.lhz.common.utils.ImportExeclUtil;
import cn.uexpo.lhz.domain.ImportLog;
import cn.uexpo.lhz.domain.Staff;
import cn.uexpo.lhz.domain.StaffExample;


/**
 * @ClassName: ImportStaffController
 * @Description:TODO(导入人员信息操作)
 * @author: 李冬建
 * @date: 2020年6月4日 上午10:28:40
 * @Copyright: 1.0.0
 */
@RestController
@RequestMapping("/admin/importStaff")
public class ImportStaffController extends BaseController<Staff> {

    @Autowired
    private StaffBiz staffBiz;
    @Autowired
    private ImportLogBiz importLogBiz;
    @Autowired
    private HttpSession session;

    public static int FILE_COUNT = 2;// 上传文件数量

    /**
     * 导入人员信息
     *
     * @return @RequestParam("uploadFiles")
     * @throws Exception
     */
    @RequestMapping(value = "/importStaff", method = {RequestMethod.GET, RequestMethod.POST})
    public String importStaff(@RequestParam(name = "createBy") String createBy,
                              @RequestParam("files") MultipartFile[] uploadFiles) throws Exception {
        String FILE_SIZE = dictionaryUtil.getItemValueUsable("biz_staff_params", "staff_pic_size");//图片大小：单位M
        System.out.println(FILE_SIZE + "------");
        String msg = "";
        MultipartFile excelFile = null;// excel文件
        MultipartFile zipFile = null;// zip文件
        boolean verifyFlag = false;//校验是否通过
        /******* 校验处理begin*********************/
        if (uploadFiles != null && uploadFiles.length > 0) {
            boolean size = checkListsize(uploadFiles);
            if (size) {
                boolean type = checkFilesType(uploadFiles);
                if (type) {
                    verifyFlag = true;//通过
                    MultipartFile multipartFile1 = uploadFiles[0];// 获取第一个文件
                    MultipartFile multipartFile2 = uploadFiles[1];// 获取第二个文件
                    boolean isExcel = checkExcel(multipartFile1);// 检查第一个文件是否为excel文件
                    // 获取excel文件和zip文件
                    if (isExcel) {
                        excelFile = multipartFile1;
                        zipFile = multipartFile2;
                    } else {
                        excelFile = multipartFile2;
                        zipFile = multipartFile1;
                    }
                } else {
                    msg = "上传文件必须是一个excel一个zip!";
                }
            } else {
                msg = "上传文件数量有误";
            }
        }
        /******* 校验处理begin *********************/

        if (!verifyFlag) {
            return msg;
        }
        /******* 解压处理begin*********************/
        List<File> files = new ArrayList<File>();// 接收zip文件中的所有图片

        //uploadFolderName：zip文件存储目录，解压后删除   unzipPath：解压缩后文件存放目录，业务处理后里面内容删除
        String uploadFolderName = "uploadFolder";//本机位置D:\EclpWork\certManage3\src\main\webapp\tempDirectory
        String unzipPath = "tempDirectory";//本机位置D:\EclpWork\certManage3\src\main\webapp\tempDirectory
        // 清除上次上传进度信息
        String curProjectPath = session.getServletContext().getRealPath("/");
        String saveDirectoryPath = curProjectPath + uploadFolderName;
        String unzipDirectoryPath = curProjectPath + unzipPath;
        System.out.println("上传保存目录：" + saveDirectoryPath);
        System.out.println("上传解压主题目录：" + unzipDirectoryPath);
        File saveDirectory = new File(saveDirectoryPath);
        if (!saveDirectory.isDirectory()) {
            saveDirectory.mkdir();
        }
        File unzipPathDirectory = new File(unzipDirectoryPath);
        if (!unzipPathDirectory.isDirectory()) {
            unzipPathDirectory.mkdir();
        }
        System.out.println("Project real path [" + saveDirectory.getAbsolutePath() + "]");
        // 判断文件是否存在
        if (!zipFile.isEmpty()) {
            String fileName = zipFile.getOriginalFilename();
            File newUploadFile = new File(saveDirectory, fileName);
            zipFile.transferTo(newUploadFile);
            // 解压缩
            try {
                files = zipToFile(saveDirectoryPath + File.separator + fileName, unzipDirectoryPath);
            } catch (Exception e) {
                del(saveDirectoryPath);//删除原上传文件
                msg = "zip文件解压失败,压缩时请选择zip格式压缩!";
                return msg;
            } finally {
                del(saveDirectoryPath);//删除原上传文件
//				newUploadFile.delete();// 该方法也可以删除原上传文件
            }
            /*******解压处理end********************/

            /******** 导入数据业务处理begin*********************/
            String excelFileName = excelFile.getOriginalFilename();
            InputStream inputStream = excelFile.getInputStream();
            Workbook wb = WorkbookFactory.create(inputStream);
            // 读取对象列表的信息
            Staff record = new Staff();
            // 第二行开始，到倒数第三行结束（总数减去两行）
            List<Staff> records = ImportExeclUtil.readDateListT(wb, record, 2, 0);
            System.out.println(records + "\n\n" + records.size());
            if (records != null && records.size() > 0) {
                for (Staff staff : records) {
                    int resultcode = 0;
                    String message = "";
                    String untitled2Flag = "0";//人员编号判断
                    String labelFlag = "0";//标签判断
                    String picFlag = "0";//图片判断
                    String recordFlag = "0";//记录判断
                    int no = 0;
                    Date currentTime = StringDate.getNow();
                    String untitled2 = staff.getUntitled2();//人员编号，excel中该字段不允许重复
                    if (StringUtils.isBlank(untitled2)) {
                        break;
                    }
                    String proLabel = staff.getProjectLabel();//标签
                    String keyword1 = staff.getUntitled2();// 人员编号
                    String keyword2 = staff.getStaffName();// 姓名
                    untitled2Flag = verifyUntitled2(untitled2);
                    labelFlag = verifyProLabel(proLabel);
                    picFlag = verifyPic(files, staff);
                    recordFlag = verifyRecord(staff);
                    //人员编号判断
                    if (untitled2Flag.equals("1")) {
                        resultcode = 101;
                        message = "人员编号已存在";
                        msg = "人员编号[" + keyword1 + "],姓名[" + keyword2 + "].提示：（" + message + ")";//详情
                        insertImportLog(staff, resultcode, createBy, excelFileName, msg);//添加到导入日志
                        resultcode = 0;
                        continue;
                    }
                    staff.setIntoTime(currentTime);
                    //标签判断
                    if (labelFlag.equals("0")) {
                        resultcode = 102;
                        message = "标签验证异常";
                    } else {
                        //图片判断
                        if (picFlag.equals("0")) {
                            resultcode = 103;
                            message = "图片不存在";
                        } else if (picFlag.equals("2")) {
                            resultcode = 104;
                            message = "图片大小不能超过" + FILE_SIZE + "M";
                        } else {
                            //图片符合要求，进一步处理
                            if (recordFlag.equals("0")) {//不存在，则添加
                                no = staffBiz.insertSelective(staff);
                                if (no == 1) {
                                    resultcode = 200;
                                    message = "操作成功";
                                } else {
                                    resultcode = 401;
                                    message = "记录插入失败";
                                }
                            } else {//存在，则更新
                                no = staffBiz.updateByPrimaryKeySelective(staff);
                                if (no == 1) {
                                    resultcode = 200;
                                    message = "操作成功";
                                } else {
                                    resultcode = 402;
                                    message = "记录更新失败";
                                }
                            }
                        }
                    }
                    String logMsg = "";
                    if (resultcode == 200) {
                        logMsg = message;
                    } else {
                        logMsg = "人员编号[" + keyword1 + "],姓名[" + keyword2 + "].提示：（" + message + ")";//详情
                    }

                    insertImportLog(staff, resultcode, createBy, excelFileName, logMsg);//添加到导入日志
                    resultcode = 0;
                }
                msg = "操作结束";


                del(unzipDirectoryPath);//删除解压后的目录及下面所有文件

            }
            /******* 导入数据业务end *********************/

        }

        return msg;
    }

    //人员编号
    private String verifyUntitled2(String untitled2) {
        String result = "0";//默认不存在
        StaffExample example = new StaffExample();
        StaffExample.Criteria citeria = example.createCriteria();
        citeria.andUntitled2EqualTo(untitled2);
        List<Staff> builders = staffBiz.selectByExample(example);
        if (builders != null && builders.size() > 0) {
            result = "1";//存在
        }
        return result;
    }

    //标签
    private String verifyProLabel(String proLabel) {
        String result = "0";//默认包含
        boolean status = proLabel.contains("，");
        if (!status) {
            result = "1";//不包含，格式正确
        }
        return result;
    }

    //图片
    private String verifyPic(List<File> files, Staff staff) throws IOException {
        String FILE_SIZE = dictionaryUtil.getItemValueUsable("biz_staff_params", "staff_pic_size");//图片大小：单位M
        String result = "0";//默认找不到图片
        String recordPicname = staff.getStaffName() + "_" + staff.getStaffTel();//从excel文件中设置图片名字
        for (File picFile : files) {
            String picfileName = picFile.getName();
            String picfileName1 = picfileName.substring(0, picfileName.indexOf("."));//获取图片名字，不带后缀
            if (recordPicname.equals(picfileName1)) {
                staff.setUntitled3(picfileName);//图片名称
                long size = picFile.length();
                if (size > Long.parseLong(FILE_SIZE) * 1024 * 1024) {
                    result = "2";//图片超过4M不符合要求
                    break;
                } else {
                    byte[] readAllBytes = Files.readAllBytes(picFile.toPath());//获取文件的字节数组
                    staff.setStaffOriginalImage(readAllBytes);
                    result = "1";//找到图片
                    break;
                }


            }
        }

        return result;
    }

    //是否有记录
    @SuppressWarnings("rawtypes")
    private String verifyRecord(Staff staff) {
        String result = "0";//默认无记录
        StaffExample example = new StaffExample();
        StaffExample.Criteria citeria = example.createCriteria();
        List staffs = null;
        if (StringUtils.isNotBlank(staff.getStaffName())
                && StringUtils.isNotBlank(staff.getProjectType())
                && StringUtils.isNotBlank(staff.getStaffTel())) {
            citeria.andStaffNameEqualTo(staff.getStaffName()).andProjectTypeEqualTo(staff.getProjectType()).andStaffTelEqualTo(staff.getStaffTel());
            staffs = staffBiz.selectByExample(example);
        }
        if (staffs != null && staffs.size() > 0) {
            result = "1";//有记录
        }
        return result;
    }


    private void insertImportLog(Staff staff, int resultcode, String createBy, String fileName, String msg) {

        ImportLog log = new ImportLog();
        Date now = StringDate.getNow();
        String keyword1 = staff.getUntitled2();// 人员编号
        String keyword2 = staff.getStaffName();// 姓名
        String keyword3 = staff.getStaffTel();// 手机号
        String keyword4 = staff.getProjectType();// 所属项目
        log.setCode(resultcode);
        log.setMsg(msg);
        log.setFilename(fileName);
        log.setKeyword1(keyword1);
        log.setKeyword2(keyword2);
        log.setKeyword3(keyword3);
        log.setKeyword4(keyword4);
        log.setCreateBy(createBy);
        log.setCreateTime(now);
        importLogBiz.insertSelective(log);
    }


    /**
     * @throws
     * @Title: checkExcel
     * @Description: TODO(excel文件校验)
     * @param: @param file
     * @param: @return
     * @param: @throws Exception
     * @return: boolean
     */
    private static boolean checkExcel(MultipartFile file) throws Exception {
        // 判断文件是否存在
        if (null == file) {
            return false;// 文件不存在
        }
        // 获得文件名
        String fileName = file.getOriginalFilename();
        if (fileName.endsWith("xls") || fileName.endsWith("xlsx")) {
            return true;// excel文件
        } else {
            return false;// 不符合要求文件
        }
    }

    /**
     * @throws
     * @Title: checkZip
     * @Description: TODO(zip文件校验)
     * @param: @param file
     * @param: @return
     * @param: @throws Exception
     * @return: boolean
     */
    private static boolean checkZip(MultipartFile file) throws Exception {
        // 判断文件是否存在
        if (null == file) {
            return false;// 文件不存在
        }
        // 获得文件名
        String fileName = file.getOriginalFilename();
        if (fileName.endsWith("zip")) {
            return true;// excel文件
        } else {
            return false;// 不符合要求文件
        }

    }

    /**
     * @throws
     * @Title: checkListsize
     * @Description: TODO(数量校验 ： 2个)
     * @param: @param files
     * @param: @return
     * @param: @throws Exception
     * @return: boolean
     */
    private static boolean checkListsize(MultipartFile[] files) throws Exception {
        if (files != null && files.length == FILE_COUNT) {
            return true;//
        } else {
            return false;// 文件个数有误
        }
    }

    /**
     * @throws
     * @Title: checkFilesType
     * @Description: TODO(文件类型校验)
     * @param: @param files
     * @param: @return
     * @param: @throws Exception
     * @return: boolean
     */
    private static boolean checkFilesType(MultipartFile[] files) throws Exception {
        MultipartFile multipartFile1 = files[0];
        MultipartFile multipartFile2 = files[1];
        boolean oneExceloneZip = (checkExcel(multipartFile1) && checkZip(multipartFile2))
                || (checkExcel(multipartFile2) && checkZip(multipartFile1));
        if (oneExceloneZip) {
            return true;
        } else {
            return false;
        }

    }

    /**
     * 解压zip文件
     *
     * @param sourceFile,待解压的zip文件; toFolder,解压后的存放路径
     * @throws Exception
     **/

    private static List<File> zipToFile(String sourceFile, String toFolder) throws Exception {
        String toDisk = toFolder;// 接收解压后的存放路径
        ZipFile zfile = new ZipFile(sourceFile, Charset.forName("GBK"));// 连接待解压文件
        List<File> files = new ArrayList<File>();// 用于接收zip里面所有文件
        Enumeration<? extends ZipEntry> zList = zfile.entries();// 得到zip包里的所有元素
        ZipEntry ze = null;
        byte[] buf = new byte[1024];
        while (zList.hasMoreElements()) {
            ze = (ZipEntry) zList.nextElement();
            if (ze.isDirectory()) {
                System.out.println("打开zip文件里的文件夹:" + ze.getName() + "skipped...");
                continue;
            }
            OutputStream outputStream = null;
            InputStream inputStream = null;
            try {
                // 以ZipEntry为参数得到一个InputStream，并写到OutputStream中
                File newFile = getRealFileName(toDisk, ze.getName());
                files.add(newFile);
                outputStream = new BufferedOutputStream(new FileOutputStream(newFile));
                inputStream = new BufferedInputStream(zfile.getInputStream(ze));
                int readLen = 0;
                while ((readLen = inputStream.read(buf, 0, 1024)) != -1) {
                    outputStream.write(buf, 0, readLen);
                }
                inputStream.close();
                outputStream.close();
            } catch (Exception e) {
                System.out.println("解压失败：" + e.toString());
                throw new IOException("解压失败：" + e.toString());
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException ex) {

                    }
                }
                if (outputStream != null) {
                    try {
                        outputStream.close();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
                inputStream = null;
                outputStream = null;
            }

        }
        zfile.close();
        return files;
    }

    /**
     * 给定根目录，返回一个相对路径所对应的实际文件名.
     *
     * @param zippath     指定根目录
     * @param absFileName 相对路径名，来自于ZipEntry中的name
     * @return java.io.File 实际的文件
     */
    private static File getRealFileName(String zippath, String absFileName) {
        System.out.println("文件名：" + absFileName);
        String[] dirs = absFileName.split("/", absFileName.length());
        File ret = new File(zippath);// 创建文件对象
        if (dirs.length > 1) {
            for (int i = 0; i < dirs.length - 1; i++) {
                ret = new File(ret, dirs[i]);
            }
        }
        if (!ret.exists()) {// 检测文件是否存在
            ret.mkdirs();// 创建此抽象路径名指定的目录
        }
        ret = new File(ret, dirs[dirs.length - 1]);// 根据 ret 抽象路径名和 child 路径名字符串创建一个新 File 实例
        return ret;
    }

    /**
     * @throws
     * @Title: del
     * @Description: TODO(删除指定目录下所有文件)
     * @param: @param filepath
     * @param: @throws IOException
     * @return: void
     */

    public void del(String filepath) throws IOException {
        File f = new File(filepath);//定义文件路径
        if (f.exists() && f.isDirectory()) {//判断是文件还是目录
            if (f.listFiles().length == 0) {//若目录下没有文件则直接删除
                f.delete();
            } else {//若有则把文件放进数组，并判断是否有下级目录
                File delFile[] = f.listFiles();
                int i = f.listFiles().length;
                for (int j = 0; j < i; j++) {
                    if (delFile[j].isDirectory()) {
                        del(delFile[j].getAbsolutePath());//递归调用del方法并取得子目录路径
                    }
                    delFile[j].delete();//删除文件
                }
            }
        }
    }


}
